(ns lastfm-music-recommendation.music
  (:require [clojure.data.json :as json]))

(defn json-request
  "Take a URL, return json object and parse it into map"
  [url]
  (with-open [stream (.openStream (java.net.URL. url))]
    (let [buf (java.io.BufferedReader. (java.io.InputStreamReader. stream))]
      (json/read buf :key-fn keyword)))) 

(defn get-tracks
  "Get the 'a' most popular tracks on Last.fm last week by country on page 'b'"
  [country a b]
  (let [response (json-request (str "http://ws.audioscrobbler.com/2.0/?method=geo.gettoptracks&country="  country
                               "&limit=" a "&format=json&page=" b "&api_key=bf7b60821bea927eb64736bd74a97bd2"))]
    (reduce (fn [result track] (assoc result (:name track) (:name (:artist track)))) 
            {} (:track (:toptracks response)))))

(defn random-song
  "Gets random song from LastFM"
  []
  (let [rnd (rand-nth (range 1 200))]
    (rand-nth (vec (get-tracks "serbia" 2 rnd)))))

(defn get-id
  "Searches for song on YouTube and returns it's id"
  [song]
  (let [response (json-request (str " https://www.googleapis.com/youtube/v3/search?part=id&maxResults=1&key=AIzaSyDEopdOfoIFAdwIVLgm516mY4RD4ALU4FQ&q="
                               (clojure.string/replace song #" " "+")))]
    (:videoId (:id (first (:items response))))))

(defn similar-tracks
  "Gets similar tracks for track"
  [[artist song]]
  (let [response (json-request (str "http://ws.audioscrobbler.com/2.0/?method=track.getsimilar&artist="
                               (clojure.string/replace artist #" " "+")
                               "&track=" (clojure.string/replace song #" " "+")
                               "&format=json&limit=10&api_key=bf7b60821bea927eb64736bd74a97bd2"))]
        (reduce (fn [result y] (if (:match y)
                                 (assoc result {(:name y) (:name (:artist y))
                                                :link (:url y)} (:match y)))) 
                {} (:track (:similartracks response)))))


(defn get-recommendation
  "Gets recommended songs"
  [scores]
  (take 10 (reverse (sort-by val (apply merge (pmap (fn [[track score]] (reduce #(assoc %1 (key %2) (* (Integer/parseInt score)
                                                                                                       (Double/parseDouble (val %2)))) 
                                                                                {} (similar-tracks track)))  
                                                    scores))))))

;(def sc {["Atoms for Peace" "Reverse Running"] "2", ["Atoms for Peace" "Amok"] "5", ["Radiohead" "All I Need"] "4"})

